﻿#include "mainWindow.h"
#include "config.h"
#include "dataUtil.h"
#include "tableUtils.h"
#include <QMessagebox>


MainWindow::MainWindow(QWidget* parent): m_config(Config::getInstance()) {
    m_ui.setupUi(this);
    connect(&m_com, &QSerialPort::readyRead, this, &MainWindow::onDataReceive);
    connect(&m_timer, &QTimer::timeout, this, &MainWindow::onTimerHandle);
}

MainWindow::~MainWindow() {
	closeSerialPort();
}

void MainWindow::init() {
	closeSerialPort();
	//刷新串口列表
    refreshComList();
	//加载配置文件
    initDirectList();
}

void MainWindow::initDirectList() {
    //初始化表格
    QMap<QString, QString> directMap = m_config.directs();
    m_ui.tableWidget->model()->removeRows(0, m_ui.tableWidget->rowCount());
    m_ui.tableWidget->setRowCount(directMap.size());
    QStringList keys = directMap.keys();
    for (int i = 0; i < keys.size(); i++) {
        TableUtils::insertValue2Table(m_ui.tableWidget, i, 0, keys[i]);
        TableUtils::insertValue2Table(m_ui.tableWidget, i, 1, directMap.value(keys[i]));
    }
}

void MainWindow::openSerialPort() {
    //关闭已经打开的串口
    closeSerialPort();
    QString comNum = m_ui.portBox->currentText().trimmed();
    if(!comNum.isEmpty()){
        m_com.setPortName(comNum);
        if (m_com.open(QIODevice::ReadWrite)) {
            int baudRate = m_ui.baudRateBox->currentText().toInt();
            int dataBits = m_ui.dataBitBox->currentIndex();
            int parity = m_ui.parityBox->currentIndex();
            int stopBits = m_ui.stopBitBox->currentIndex();
            int flowControl = m_ui.flowControlBox->currentIndex();
            setPortProperty(baudRate, dataBits, parity, stopBits, flowControl);
            showMsg(m_ui.portStatusLabel, tr("串口已打开"), OK);
        } else {
            showMsg(m_ui.portStatusLabel, tr("串口打开失败"), ERROR);
        }
    }
}

void MainWindow::refreshComList() {
    QList<QSerialPortInfo> portList = QSerialPortInfo::availablePorts();
    m_ui.portBox->clear();
    for (QSerialPortInfo info : portList) {
        m_ui.portBox->addItem(info.portName());
    }
}

void MainWindow::setPortProperty(int baudRate, int dataBits, int parity, int stopBits, int flowControl) {
    m_com.setBaudRate(baudRate);
	switch (dataBits) {
        case 0: m_com.setDataBits(QSerialPort::Data5); break;
        case 1: m_com.setDataBits(QSerialPort::Data6); break;
        case 2: m_com.setDataBits(QSerialPort::Data7); break;
        case 3: m_com.setDataBits(QSerialPort::Data8); break;
	}
	switch (parity) {
        case 0: m_com.setParity(QSerialPort::NoParity); break;
        case 1: m_com.setParity(QSerialPort::EvenParity); break;
        case 2: m_com.setParity(QSerialPort::OddParity); break;
        case 3: m_com.setParity(QSerialPort::SpaceParity); break;
        case 4: m_com.setParity(QSerialPort::MarkParity); break;
	}
	switch (stopBits) {
        case 0: m_com.setStopBits(QSerialPort::OneStop); break;
        case 1: m_com.setStopBits(QSerialPort::OneAndHalfStop); break;
        case 2: m_com.setStopBits(QSerialPort::TwoStop); break;
	}
	switch (flowControl) {
        case 0: m_com.setFlowControl(QSerialPort::NoFlowControl); break;
        case 1: m_com.setFlowControl(QSerialPort::HardwareControl); break;
        case 2: m_com.setFlowControl(QSerialPort::SoftwareControl); break;
	}
}

void MainWindow::closeSerialPort() {
	//删除已经打开的串口
    if (m_com.isOpen()) {
        m_com.clear();
        m_com.close();
	}
    showMsg(m_ui.portStatusLabel, "请选择串口", OK);
}

void MainWindow::fillCheckcode(QByteArray& data) {
    //判断校验类型
    int checkModel = m_ui.checkListComboBox->currentIndex();
    if (checkModel > 0) {
        //获取校验位起始和终止位
        int begin = m_ui.checkBeginSpinBox->value();
        int end = m_ui.checkEndSpinBox->value();
        switch (checkModel) {
            case 1: DataUtil::crc16ModbusCheck(data, begin, end); break;
            case 2: DataUtil::bccCheck(data, begin, end); break;
            case 3: DataUtil::lrcCheck(data, begin, end); break;
            case 4: DataUtil::bd2Check(data); break;
        }
    }
}

void MainWindow::showMsg(QLabel* label, const QString& msg, int type) {
	label->setText(msg);
	if (type == OK) {
		label->setStyleSheet(QString::fromUtf8("color: rgb(85, 170, 127);"));
	} else {
		label->setStyleSheet(QString::fromUtf8("color: red;"));
	}
}

bool MainWindow::sendData() {
    if (m_com.isOpen()) {
        QString data = m_ui.lineEdit->text();
        if (data.isEmpty()) {
            QMessageBox::warning(this, "警告", "发送数据不能为空", "关闭");
            return false;
        }
        QByteArray buffer;
        //判断发送数据的方式
        if (m_ui.hexSendCheckBox->isChecked()) {
            bool ok = DataUtil::hex2Ascii(data, buffer);
            if (!ok) {
                QMessageBox::warning(this, "警告", "非法的数据", "关闭");
                return false;
            }
        } else {
            buffer = data.toLocal8Bit();
        }
        //计算校验码
        fillCheckcode(buffer);
        //判断是否加入回车换行
        if (m_ui.addNewLineCheckBox->isChecked()) {
            buffer.append(0x0d);
            buffer.append(0x0a);
        }
        try {
            //发送数据
            sendData(buffer);
            return true;
        } catch (const std::exception& e) {
            qCritical() << e.what();
        } catch (...) {
            qCritical() << "unknow error...";
        }
    } else {
        QMessageBox::warning(this, "警告", "串口未打开", "关闭");
    }
    return false;
}

void MainWindow::sendData(QByteArray &data) {
    if(m_com.isOpen()){
        try {
            m_com.write(data);
            m_com.flush();
            if (m_com.waitForBytesWritten()) {
                //判断是否要显示发送的数据
                QStringList textList;
                if (m_ui.showSendDataBox->isChecked()) {
                    QDateTime now = QDateTime::currentDateTime();
                    textList << tr("[%1]").arg(now.toString("yyyy/MM/dd hh:mm:ss"));
                }
                textList << "发：";
                if (m_ui.hexSendCheckBox->isChecked()) {
                    textList << data.toHex(' ');
                } else {
                    textList << QString::fromLocal8Bit(data);
                }
                m_ui.plainTextEdit->appendPlainText(textList.join(" "));
            }
        } catch (...) {
            qCritical() << "data send error...";
        }
    }
}

void MainWindow::onTimerHandle() {
    try {
        if (!sendData()) {
            QMessageBox::warning(this, "警告", "数据发送失败", "关闭");
            //停止定时器并初始化按钮等组件的状态
            m_timer.stop();
            m_ui.sendDataBtn->setText(tr("开始"));
            m_ui.sendDataBtn->setStyleSheet("background-color: rgb(85, 170, 255);");
            m_ui.timerSendSpinBox->setEnabled(true);
            m_ui.timerSendBox->setEnabled(true);
        }
    } catch (const std::exception& e) {
        qCritical() << e.what();
    } catch (...) {
        qCritical() << "data send error...";
    }
}

void MainWindow::onDataReceive() {
    QByteArray buf = m_com.readAll();
    while(m_com.bytesAvailable() > 0){
        buf.append(m_com.readAll());
        m_com.waitForReadyRead(100);
    }
    QStringList textList;
    //判断是否显示时间
    if (m_ui.showTimeBox->isChecked()) {
        QDateTime now = QDateTime::currentDateTime();
        textList << tr("[%1]").arg(now.toString("yyyy/MM/dd HH:mm:ss"));
    }
    textList << "收：";
    //判断显示方式
    if (m_ui.rHexRadioBtn->isChecked()) {
        //以Hex方式显示
        textList << buf.toHex(' ');
    } else {
        textList << QString::fromLocal8Bit(buf);
    }
    m_ui.plainTextEdit->appendPlainText(textList.join(" "));

}

void MainWindow::on_openBtn_clicked() {
     if (m_com.isOpen()) {
     	//串口已经打开，关闭串口
     	closeSerialPort();
     	m_ui.openBtn->setStyleSheet(QString::fromUtf8("QPushButton {background-color: rgb(85, 170, 255);}"));
        m_ui.openBtn->setText(tr("打开"));
     } else {
     	//串口未打开，打开串口
     	openSerialPort();
     	if (m_com.isOpen()) {
            m_ui.openBtn->setStyleSheet(QString::fromUtf8("QPushButton {background-color: rgb(255, 0, 0);}"));
            m_ui.openBtn->setText(tr("关闭"));
     	}
     }
}

void MainWindow::on_clearReceiveBtn_clicked() {
    m_ui.plainTextEdit->clear();
}

void MainWindow::on_addDirectiveBtn_clicked() {
    QString name = m_ui.directNameLineEdit->text().trimmed();
    QString val = m_ui.directLineEdit->text();
    QStringList keys = m_config.directs().keys();
    if (name.isEmpty()) {
        QMessageBox::warning(this, "警告", "数据发送失败", "关闭");
        return;
    }
    if (keys.contains(name)) {
        if (QMessageBox::warning(this, "警告", "已存在相同名称的指令，是否覆盖", "是", "否")) {
            return;
        }
    }
    //添加指令到配置文件
    m_config.addDirect(name, val);
    //添加指令到表格
    m_ui.tableWidget->insertRow(0);
    TableUtils::insertValue2Table(m_ui.tableWidget, 0, 0, name);
    TableUtils::insertValue2Table(m_ui.tableWidget, 0, 1, val);
}

void MainWindow::on_deleteDirectiveBtn_clicked() {
    QList<QTableWidgetItem*>  items = m_ui.tableWidget->selectedItems();
    if (items.size() > 1 && items[1]  != nullptr) {
        int row = items[1]->row();
        if (QMessageBox::warning(this, "警告", "是否删除当前选中的指令", "是", "否")) {
            return;
        }
        //删除指令
        QString name = items[0]->text();
        m_config.deleteDirect(name);
        m_ui.tableWidget->removeRow(row);
    }
}

void MainWindow::on_refreshComListBtn_clicked() {
    refreshComList();
}

void MainWindow::on_timerSendBox_checkStateChanged(const Qt::CheckState& state) {
    if (state == Qt::CheckState::Checked) {
        //判断定时发送时间是否大于0
        int time = m_ui.timerSendSpinBox->value();
        if (time > 0) {
            m_ui.sendDataBtn->setText("开始");
        } else {
            QMessageBox::warning(this, "警告", "定时时间不能为0", "关闭");
            m_ui.timerSendBox->setChecked(false);
            return;
        }
    } else {
        m_ui.sendDataBtn->setText("发送");
    }
}

void MainWindow::on_sendDataBtn_clicked() {
    //判断是否是定时器发送
    if (m_ui.timerSendBox->isChecked()) {
        if (m_ui.sendDataBtn->text() == "开始") {
            //先发送一次数据
            try {
                if (sendData()) {
                    //禁用复选框和时间输入按钮
                    m_ui.timerSendSpinBox->setEnabled(false);
                    m_ui.timerSendBox->setEnabled(false);
                    //启动定时器
                    if (!m_timer.isActive()) {
                        m_timer.start(m_ui.timerSendSpinBox->value());
                    }
                    m_ui.sendDataBtn->setText(tr("停止"));
                    m_ui.sendDataBtn->setStyleSheet("background-color: rgb(255, 0, 0);");
                } else {
                    QMessageBox::warning(this, "警告", "数据发送失败", "关闭");
                }
            } catch (const std::exception& e) {
                qCritical() << e.what();
            } catch (...) {
                qCritical() << "unknow error...";
            }
        } else {
            m_timer.stop();
            m_ui.sendDataBtn->setText(tr("开始"));
            m_ui.sendDataBtn->setStyleSheet("background-color: rgb(85, 170, 255);");
            m_ui.timerSendSpinBox->setEnabled(true);
            m_ui.timerSendBox->setEnabled(true);
        }
    } else {
        //发送数据
        try {
            if (!sendData()) {
                QMessageBox::warning(this, "警告", "数据发送失败", "关闭");
            }
        } catch (const std::exception& e) {
            qCritical() << e.what();
        } catch (...) {
            qCritical() << "unknow error...";
        }
    }
}

void MainWindow::on_tableWidget_cellDoubleClicked(int row, int column) {
    if (row >= 0) {
        if (m_ui.tableWidget->item(row, column) != nullptr) {
            QString data = m_ui.tableWidget->item(row, column)->text();
            QByteArray buffer;
            //判断发送数据的方式
            if (m_ui.hexSendCheckBox->isChecked()) {
                bool ok = DataUtil::hex2Ascii(data, buffer);
                if (!ok) {
                    QMessageBox::warning(this, "警告", "非法的数据", "关闭");
                    return;
                }
            } else {
                buffer = data.toLocal8Bit();
            }
            //发送数据
            try {
                sendData(buffer);
            } catch (const std::exception& e) {
                qCritical() << e.what();
            } catch (...) {
                qCritical() << "unknow error...";
            }
        }
    }
}


